package fr.lip6.move.care;

import com.google.common.collect.Iterables;
import fr.lip6.move.care.CareActorGen;
import fr.lip6.move.care.CareAltGen;
import fr.lip6.move.care.CareCallGen;
import fr.lip6.move.care.CareDiagramGen;
import fr.lip6.move.care.CareDiagramRefGen;
import fr.lip6.move.care.CareLoopGen;
import fr.lip6.move.care.CareObjGen;
import fr.lip6.move.care.CareOptGen;
import fr.lip6.move.care.CompileResult;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
import sdmakerz_v1.coresyntax.SDMakerV1RuntimeModule;
import sdmakerz_v1.coresyntax.generator.SDMakerV1IDProvider;
import sdmakerz_v1.coresyntax.generator.interfaces.IConfigData;
import sdmakerz_v1.coresyntax.generator.interfaces.IContext;
import sdmakerz_v1.coresyntax.generator.interfaces.IDiagramRefData;
import sdmakerz_v1.coresyntax.generator.interfaces.IInputData;
import sdmakerz_v1.coresyntax.generator.interfaces.ISDMakerModelLevelGen;
import sdmakerz_v1.coresyntax.sDMakerV1.Actor;
import sdmakerz_v1.coresyntax.sDMakerV1.Alt;
import sdmakerz_v1.coresyntax.sDMakerV1.Call;
import sdmakerz_v1.coresyntax.sDMakerV1.Diagram;
import sdmakerz_v1.coresyntax.sDMakerV1.DiagramElement;
import sdmakerz_v1.coresyntax.sDMakerV1.DiagramRef;
import sdmakerz_v1.coresyntax.sDMakerV1.Loop;
import sdmakerz_v1.coresyntax.sDMakerV1.Obj;
import sdmakerz_v1.coresyntax.sDMakerV1.Opt;
import sdmakerz_v1.coresyntax.sDMakerV1.SDMakerModel;

/**
 * La classe principale de generation vers CARE
 * 
 * @author pstl-team
 */
@SuppressWarnings("all")
public class CareGen implements ISDMakerModelLevelGen {
  /**
   * Un element doit etre ajoute dans la sequence principale
   * si il n'est inclut dans aucun autre et qu'il represente un
   * un element existant dans CARE. Il sera alors ajouter a la BlockList
   * principale du Main (voir utilisation de la classe Main dans le package
   * programs de CARE). Par exemple, une declaration de methode n'as pas
   * d'equivalent en CARE.
   */
  private List<CompileResult> mainSequence;
  
  private CareActorGen actorGen;
  
  private CareAltGen altGen;
  
  private CareCallGen callGen;
  
  private CareDiagramGen diagramGen;
  
  private CareDiagramRefGen diagramRefGen;
  
  private CareLoopGen loopGen;
  
  private CareObjGen objGen;
  
  private CareOptGen optGen;
  
  public CareGen() {
    CareActorGen _careActorGen = new CareActorGen(this);
    this.actorGen = _careActorGen;
    CareAltGen _careAltGen = new CareAltGen(this);
    this.altGen = _careAltGen;
    CareCallGen _careCallGen = new CareCallGen(this);
    this.callGen = _careCallGen;
    CareDiagramGen _careDiagramGen = new CareDiagramGen(this);
    this.diagramGen = _careDiagramGen;
    CareDiagramRefGen _careDiagramRefGen = new CareDiagramRefGen(this);
    this.diagramRefGen = _careDiagramRefGen;
    CareLoopGen _careLoopGen = new CareLoopGen(this);
    this.loopGen = _careLoopGen;
    CareObjGen _careObjGen = new CareObjGen(this);
    this.objGen = _careObjGen;
    CareOptGen _careOptGen = new CareOptGen(this);
    this.optGen = _careOptGen;
  }
  
  public boolean canHandle(final Resource input) {
    boolean canHandle = false;
    TreeIterator<EObject> _allContents = input.getAllContents();
    Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_allContents);
    for (final EObject eo : _iterable) {
      if ((eo instanceof SDMakerModel)) {
        canHandle = true;
      }
    }
    return canHandle;
  }
  
  public boolean addToMainSequence(final CompileResult compRes) {
    boolean _add = this.mainSequence.add(compRes);
    return _add;
  }
  
  public List<CompileResult> getMainSequence() {
    return this.mainSequence;
  }
  
  public void doGenerate(final IContext context, final IFileSystemAccess fsa) {
    try {
      IInputData inputData = context.getInputData();
      Resource input = inputData.getInput();
      TreeIterator<EObject> _allContents = input.getAllContents();
      Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_allContents);
      Iterable<Diagram> _filter = Iterables.<Diagram>filter(_iterable, Diagram.class);
      for (final Diagram diagram : _filter) {
        {
          Class<? extends IConfigData> _bindIConfigData = SDMakerV1RuntimeModule.bindIConfigData();
          IConfigData configData = _bindIConfigData.newInstance();
          Class<? extends IDiagramRefData> _bindIDiagramRefData = SDMakerV1RuntimeModule.bindIDiagramRefData();
          IDiagramRefData refData = _bindIDiagramRefData.newInstance();
          configData.init(null);
          String _name = diagram.getName();
          refData.init(diagram, null, null, _name);
          context.setContextDiagram(diagram);
          context.setConfigData(configData);
          context.setDiagramRefData(refData);
          ArrayList<CompileResult> _arrayList = new ArrayList<CompileResult>();
          this.mainSequence = _arrayList;
          SDMakerV1IDProvider.reinitIDs();
          String _outputBasedName = inputData.getOutputBasedName();
          String _plus = ("care-gen/" + _outputBasedName);
          String _plus_1 = (_plus + "_");
          String _name_1 = diagram.getName();
          String _plus_2 = (_plus_1 + _name_1);
          String _plus_3 = (_plus_2 + ".java");
          CompileResult _compile = this.diagramGen.compile(context, diagram);
          CharSequence _charSequenceResult = _compile.getCharSequenceResult();
          fsa.generateFile(_plus_3, _charSequenceResult);
        }
      }
    } catch (Exception _e) {
      throw Exceptions.sneakyThrow(_e);
    }
  }
  
  public CompileResult compile(final IContext context, final DiagramElement elt) {
    CompileResult _switchResult = null;
    boolean _matched = false;
    if (!_matched) {
      if (elt instanceof Actor) {
        final Actor _actor = (Actor)elt;
        _matched=true;
        CompileResult _compile = this.actorGen.compile(context, ((Actor) _actor));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      if (elt instanceof Obj) {
        final Obj _obj = (Obj)elt;
        _matched=true;
        CompileResult _compile = this.objGen.compile(context, ((Obj) _obj));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      if (elt instanceof Call) {
        final Call _call = (Call)elt;
        _matched=true;
        CompileResult _compile = this.callGen.compile(context, ((Call) _call));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      if (elt instanceof Alt) {
        final Alt _alt = (Alt)elt;
        _matched=true;
        CompileResult _compile = this.altGen.compile(context, ((Alt) _alt));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      if (elt instanceof Loop) {
        final Loop _loop = (Loop)elt;
        _matched=true;
        CompileResult _compile = this.loopGen.compile(context, ((Loop) _loop));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      if (elt instanceof Opt) {
        final Opt _opt = (Opt)elt;
        _matched=true;
        CompileResult _compile = this.optGen.compile(context, ((Opt) _opt));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      if (elt instanceof DiagramRef) {
        final DiagramRef _diagramRef = (DiagramRef)elt;
        _matched=true;
        CompileResult _compile = this.diagramRefGen.compile(context, ((DiagramRef) _diagramRef));
        _switchResult = _compile;
      }
    }
    if (!_matched) {
      StringConcatenation _builder = new StringConcatenation();
      _builder.append("CareGen.compile(IContext context, DiagramElement elt): ");
      _builder.newLine();
      _builder.append("not supported DiagramElement: ");
      Class<? extends Object> _class = elt.getClass();
      String _name = _class.getName();
      _builder.append(_name, "");
      CompileResult _compileResult = new CompileResult(_builder, 
        null, 
        true);
      return _compileResult;
    }
    return _switchResult;
  }
}
